package com.ruoyi.common.utils;

import org.apache.poi.ss.usermodel.*;
import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.OutputStream;
import java.lang.reflect.Field;
import java.net.URLEncoder;
import java.util.List;

/**
 * Excel导出工具类，支持相同值单元格合并
 */
public class ExcelMergeUtil {

    /**
     * 导出Excel并合并相同值的单元格
     * @param response HTTP响应对象
     * @param dataList 数据列表
     * @param titles 表头标题数组
     * @param fieldNames 对应的数据字段名数组
     * @param fileName 导出文件名
     * @param mergeColumns 需要合并的列索引数组
     * @throws Exception 可能抛出的异常
     */
    public static <T> void exportWithMerge(HttpServletResponse response, List<T> dataList,
                                           String[] titles, String[] fieldNames,
                                           String fileName, int[] mergeColumns) throws Exception {
        // 创建工作簿
        Workbook workbook = new XSSFWorkbook();
        // 创建工作表
        Sheet sheet = workbook.createSheet("数据");

        // 设置响应头
        setResponseHeader(response, fileName);

        // 创建表头
        createHeader(sheet, titles);

        // 填充数据
        fillData(sheet, dataList, fieldNames);

        // 合并相同值的单元格
        if (mergeColumns != null && mergeColumns.length > 0) {
            for (int column : mergeColumns) {
                mergeSameCells(sheet, column, 1, dataList.size());
            }
        }

        // 输出到响应流
        try (OutputStream os = response.getOutputStream()) {
            workbook.write(os);
            os.flush();
        } finally {
            workbook.close();
        }
    }

    /**
     * 设置响应头信息
     */
    private static void setResponseHeader(HttpServletResponse response, String fileName) throws IOException {
        response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
        response.setCharacterEncoding("UTF-8");
        String encodedFileName = URLEncoder.encode(fileName, "UTF-8").replaceAll("\\+", "%20");
        response.setHeader("Content-disposition", "attachment;filename*=UTF-8''" + encodedFileName + ".xlsx");
    }

    /**
     * 创建表头
     */
    private static void createHeader(Sheet sheet, String[] titles) {
        Row headerRow = sheet.createRow(0);
        for (int i = 0; i < titles.length; i++) {
            Cell cell = headerRow.createCell(i);
            cell.setCellValue(titles[i]);
            // 设置表头样式（可选）
            CellStyle style = sheet.getWorkbook().createCellStyle();
            Font font = sheet.getWorkbook().createFont();
            font.setBold(true);
            style.setFont(font);
            style.setAlignment(HorizontalAlignment.CENTER);
            style.setVerticalAlignment(VerticalAlignment.CENTER);
            cell.setCellStyle(style);
        }
    }

    /**
     * 填充数据到工作表
     */
    private static <T> void fillData(Sheet sheet, List<T> dataList, String[] fieldNames) throws Exception {
        if (dataList == null || dataList.isEmpty()) {
            return;
        }

        for (int i = 0; i < dataList.size(); i++) {
            T data = dataList.get(i);
            Row row = sheet.createRow(i + 1); // 从第1行开始（0是表头）

            for (int j = 0; j < fieldNames.length; j++) {
                Cell cell = row.createCell(j);
                String fieldName = fieldNames[j];

                // 使用反射获取字段值
                Field field = data.getClass().getDeclaredField(fieldName);
                field.setAccessible(true);
                Object value = field.get(data);

                if (value != null) {
                    cell.setCellValue(value.toString());
                }
            }
        }
    }

    /**
     * 合并相同值的单元格
     * @param sheet 工作表
     * @param column 列索引
     * @param startRow 开始行索引（数据行开始索引）
     * @param endRow 结束行索引（数据行结束索引）
     */
    private static void mergeSameCells(Sheet sheet, int column, int startRow, int endRow) {
        if (startRow >= endRow) {
            return;
        }

        // 记录合并的起始行
        int mergeStart = startRow;
        // 获取起始单元格的值
        String firstValue = getCellValue(sheet.getRow(startRow).getCell(column));

        for (int i = startRow + 1; i <= endRow; i++) {
            Row currentRow = sheet.getRow(i);
            if (currentRow == null) {
                continue;
            }

            Cell currentCell = currentRow.getCell(column);
            String currentValue = getCellValue(currentCell);

            // 如果当前值与起始值不同，则合并从mergeStart到i-1的单元格
            if (!firstValue.equals(currentValue)) {
                if (i - 1 > mergeStart) {
                    sheet.addMergedRegion(new CellRangeAddress(mergeStart, i - 1, column, column));
                }
                // 更新起始值和起始行
                firstValue = currentValue;
                mergeStart = i;
            }

            // 处理最后一行
            if (i == endRow && i > mergeStart) {
                sheet.addMergedRegion(new CellRangeAddress(mergeStart, i, column, column));
            }
        }
    }

    /**
     * 获取单元格的值
     */
    private static String getCellValue(Cell cell) {
        if (cell == null) {
            return "";
        }

        String value = "";
        switch (cell.getCellType()) {
            case STRING:
                value = cell.getStringCellValue();
                break;
            case NUMERIC:
                if (DateUtil.isCellDateFormatted(cell)) {
                    value = cell.getDateCellValue().toString();
                } else {
                    value = String.valueOf(cell.getNumericCellValue());
                }
                break;
            case BOOLEAN:
                value = String.valueOf(cell.getBooleanCellValue());
                break;
            case FORMULA:
                value = cell.getCellFormula();
                break;
            default:
                value = "";
        }
        return value;
    }
}
